/**
 *
 */
package vn.smartware.co.framework.swt.base;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import vn.smartware.co.framework.action.Requester;
import vn.smartware.co.framework.common.BaseConstant;
import vn.smartware.co.framework.exception.ClientException;
import vn.smartware.co.framework.exception.FatalException;
import vn.smartware.co.framework.exception.SessionTimeOutException;
import vn.smartware.co.framework.form.ActionForm;
import vn.smartware.co.framework.form.CommonSearchForm;
import vn.smartware.co.framework.plugin.LangResources;
import vn.smartware.co.framework.utils.MsgBoxUtils;
import vn.smartware.co.java.net.commons.Utils;

/**
 * JNetShell
 */
abstract public class JNetShell extends Shell {

	private static Log log = LogFactory.getLog(JNetShell.class);

	private String appName;
	private Object result;
	private ActionForm searchCriteria;
	
	/**
	 * Launch the application.
	 * @param args
	 */
	public static void main(String args[]) {
		try {
			Display display = Display.getDefault();
			JNetShell shell = new JNetShell(display){};
			shell.open();
			shell.layout();
			while (!shell.isDisposed()) {
				if (!display.readAndDispatch()) {
					display.sleep();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Create the shell.
	 * @param display
	 */
	public JNetShell(Display display) {
		super(display, SWT.SHELL_TRIM);
		createContents();
	}
	
	/**
	 * Constructor
	 * @param parent
	 * @param appName 
	 * @param size 
	 * @param searchCriteria
	 * @wbp.parser.constructor
	 */
	public JNetShell(Shell parent, String appName, Point size) {
		super(parent.getDisplay(), SWT.DIALOG_TRIM);
		setSize(size);
		setText(appName);
		setToolTipText(appName);
		setBackground(BaseConstant.COLOR_BGR_BASE);
		this.appName = appName;
		createContents();
	}

	/**
	 * Initialize Shell
	 */
	private void createContents() {
		int sizeX = 600;
		int sizeY = 500;
		if (null != this.getSize()) {
			sizeX = this.getSize().x;
			sizeY = this.getSize().y;
		}
		if (getParent() != null) {
			this.setLocation(getParent().getLocation().x + (getParent().getSize().x - sizeX) / 2 + 10, 
					 		 getParent().getLocation().y + (getParent().getSize().y - sizeY) / 2 + 10);
		}
		else {
			this.setLocation(0, 0);
		}
		
		this.addListener(SWT.Traverse, new Listener() {
		    public void handleEvent(Event e) {
		        if (e.detail == SWT.TRAVERSE_ESCAPE) {
		            e.doit = false;
		            closeAction(true);
		        }
		    }
		});
		
		executeInitialize();
		
		addSelectAllListener(this);
	}

	/**
	 * execute Initialize for the Extended Class
	 */
	private void executeInitialize(){
		initialize();
		clearAction();
		displaySearchCriteria();
		if (!Utils.isNullEmpty(this.searchCriteria)) {
			CommonSearchForm form = (CommonSearchForm)searchCriteria;
			if (form.isAutoSearch()) {
				displayAction();
			}
		}
	}
	
	/**
	 * initialize
	 */
	protected void initialize() {}
	
	/**
	 * display Search Criteria
	 */
	protected void displaySearchCriteria() {}

	/**
	 * execute
	 * 
	 * @param form
	 * @return ActionForm
	 * @throws FatalException 
	 * @throws SessionTimeOutException 
	 */
	protected ActionForm execute(ActionForm form) throws FatalException,
			SessionTimeOutException {
		
		form.setAppName(this.appName);
		form = Requester.execute(form, this);
		return form;
	}

	/**
	 * validatorErrorMsgBox
	 * 
	 * @param errMsg
	 */
	protected final void validatorErrorMsgBox(String errMsg) {
		try {
			if (errMsg != null) {
				MsgBoxUtils.errorMsgBox("errors.SYSTEM_ERROR", new Object[] { errMsg });
			}
		} catch (ClientException e) {
			log.error("JNetShell validatorErrorMsgBox ClientException.", e);
		}
	}

	/**
	 * fatalErrorMsgBox
	 */
	protected final void fatalErrorMsgBox() {
		
		try {
			MsgBoxUtils.errorMsgBox("errors.SYSTEM_ERROR", new Object[] {});
		} catch (ClientException ce) {
			log.error("JNetShell fatalErrorMsgBox ClientException.", ce);
		}

		this.setFocus();
		lockScreen(true);
	}
	
	/**
	 * lock/unlock screen control
	 * @param controls
	 */
	protected void lockScreen(boolean flg) {
		
		if (flg){
			lockScreen(this.getChildren());
		}else{
			unlockScreen(this.getChildren());
		}
	}

	/**
	 * lock screen
	 * @param controls
	 */
	private void lockScreen(Control[] controls) {
		
		for (int i = 0; i < controls.length; i++) {
			Control item = controls[i];
			if (item instanceof Group){
				Group grp = (Group)item;
				lockScreen(grp.getChildren());
			} else {
				if (item instanceof Button) {
					Button btn = (Button) item;
					if (btn.getText().equals(LangResources.getText("btnClose"))){
						btn.setEnabled(true);
					}else{
						btn.setEnabled(false);
					}
					
				}else if (!(item instanceof Composite)) {
					item.setEnabled(false);
					
				} else {
					Composite comp = (Composite) item;
					lockScreen(comp.getChildren());
				}
			}
		}
	}
	
	/**
	 * unlock screen
	 * @param controls
	 */
	protected void unlockScreen(Control[] controls) {
		
		for (int i = 0; i < controls.length; i++) {
			Control item = controls[i];
			if (item instanceof Group){
				Group grp = (Group)item;
				unlockScreen(grp.getChildren());
				
			} else if (!(item instanceof Composite)) {
				item.setEnabled(true);
				
			} else {
				Composite comp = (Composite) item;
				unlockScreen(comp.getChildren());
			}
		}
	}
	
	/**
	 * SelectAllFocusAdapter
	 */
	protected final class SelectAllFocusAdapter extends FocusAdapter {
		
		/**
		 * SelectAllFocusAdapter
		 */
		public SelectAllFocusAdapter() {
			super();
		}

		/**
		 * focusGained
		 * 
		 * @param e
		 */
		public void focusGained(FocusEvent e) {
			if (e.getSource() instanceof Text) {
				((Text) e.getSource()).selectAll();
			}
		}
	}

	/**
	 * addFocusListener
	 * 
	 * @param control
	 * @param listener
	 */
	protected void addFocusListener(Control control, FocusListener listener) {
		control.addFocusListener(listener);
	}

	/**
	 * addSelectAllListener
	 * 
	 * @param ctrl
	 */
	private void addSelectAllListener(Control ctrl) {
		if (ctrl instanceof Text) {
			ctrl.addFocusListener(new SelectAllFocusAdapter());
		} else if (ctrl instanceof Composite) {
			Composite comp = (Composite) ctrl;
			Control[] children = comp.getChildren();
			if (children != null) {
				for (int i = 0; i < children.length; i++) {
					addSelectAllListener(children[i]);
				}
			}
		}
	}

	/**
	 * disposeChild
	 */
	protected void disposeChild() {
		log.debug("Dispose " + this.getClass().getName() + " control.");
		Control[] control = this.getChildren();
		for (int i = 0; i < control.length; i++) {
			control[i].dispose();
		}
	}
	
	/**
	 * clear action
	 *
	 */
	protected void clearAction() {}
	
	/**
	 * display action
	 *
	 */
	protected void displayAction() {}
	
	/**
	 * save action
	 *
	 */
	protected void saveAction() {}
	
	/**
	 * delete action
	 *
	 */
	protected void deleteAction() {}
	
	/**
	 * edit action
	 *
	 */
	protected void editAction() {}
	
	/**
	 * create new action
	 *
	 */
	protected void newAction() {}
	
	/**
	 * apply action when click button Apply
	 *
	 */
	protected void applyAction() {}
	
	/**
	 * select action when click button Select
	 *
	 */
	protected void selectAction() {}
	
	/**
	 * close business program when press key ESC
	 * or click button Close
	 * 
	 * @param appName
	 * @return boolean
	 */
	private final boolean closeAction() {
		try {
			int res = MsgBoxUtils.questionMsgBox("question.EXIT_PRG", new Object[] { this.appName });
			if (res == SWT.YES) {
				this.dispose();
				log.debug("Disposed " + this.getClass().getName());
				return true;
			}

		} catch (ClientException e) {
			log.error("ClientException.", e);
		}
		return false;
	}
	
	/**
	 * close business program when press key ESC
	 * or click button Close without confirmation
	 * 
	 * @param appName
	 * @param isConfirmed
	 * @return boolean
	 */
	protected final boolean closeAction(boolean isConfirmed) {
		if (isConfirmed){
			return closeAction();
		} else {
			this.dispose();
			log.debug("Disposed " + this.getClass().getName());
			return true;
		}
	}

	/**
	 * @return the result
	 */
	public Object getResult() {
		return result;
	}

	/**
	 * @param result the result to set
	 */
	public void setResult(Object result) {
		this.result = result;
	}

	/**
	 * @return the searchCriteria
	 */
	public ActionForm getSearchCriteria() {
		return searchCriteria;
	}

	/**
	 * @param searchCriteria the searchCriteria to set
	 */
	public void setSearchCriteria(ActionForm searchCriteria) {
		this.searchCriteria = searchCriteria;
	}
}
